#include "data.hpp"
#include "httplib.h"

// 这段代码定义了一个名为 Server 的类，它实现了一个基于 httplib 库的 HTTP 服务器，提供了与视频数据相关的 CRUD（创建、读取、更新、删除）操作。
// 该服务器与文件系统及数据库交互，能够处理视频和图片文件的上传、查询、修改和删除。以下是代码的详细分析：
namespace aod
{
#define WWWROOT "./www"
#define VIDEO_ROOT "/video/"
#define IMAGE_ROOT "/image/"
	// WWWROOT：定义静态资源的根目录，即文件系统中存储视频和图片的文件夹路径。
	// VIDEO_ROOT 和 IMAGE_ROOT：分别定义存储视频和图片的子目录。

	TableVideo *tb_video = NULL;

	// Server 类通过 httplib::Server 实现了一个简单的 HTTP 服务器。它包含了处理 HTTP 请求的方法，并且将不同的路由与处理函数关联。
	class Server
	{
	private:
		// _port：服务器监听的端口号。
		// _srv：httplib::Server 类型的实例，用于启动和管理 HTTP 服务器。
		int _port;
		httplib::Server _srv;

	private:
		// 这个方法处理上传视频及其相关信息的 POST 请求。
		// 它首先检查请求中是否包含所需的文件字段：视频名称、简介、视频文件和图片文件。
		// 如果请求无效，返回 HTTP 400（错误请求），并包含错误信息。
		// 然后，它从请求中提取文件和数据，保存视频和图片到指定目录下，构建相应的数据库记录，并插入到 tb_video 数据库表中。
		// 如果一切顺利，服务器会返回 HTTP 303 重定向到 /index.html 页面。
		static void Insert(const httplib::Request &req, httplib::Response &rsp)
		{
			if (req.has_file("name") == false ||
				req.has_file("info") == false ||
				req.has_file("video") == false ||
				req.has_file("image") == false)
			{

				rsp.status = 400;
				// 这是C++中使用原始字符串字面量（Raw String Literals）的一个示例。R"(...)"语法允许我们定义包含特殊字符（比如引号、换行符等）的字符串，而不需要进行转义。
				// {} 这是一个标准的JSON格式字符串，表示服务器返回的响应内容。JSON（JavaScript Object Notation）是一种轻量级的数据交换格式，广泛用于客户端与服务器之间的数据通信。
				rsp.body = R"({"result":false, "reason":"上传的数据信息错误"})";
				// 通常出现在处理HTTP响应的代码中，尤其是在C++编写的Web服务或API服务器中。它的作用是设置HTTP响应头中的 Content-Type 字段，告诉客户端返回的数据格式是什么。
				// 在这个例子中，Content-Type 被设置为 "application/json"，意味着服务器将返回JSON格式的数据。
				rsp.set_header("Content-Type", "application/json");
				return;
			}
			httplib::MultipartFormData name = req.get_file_value("name");	// 视频名称
			httplib::MultipartFormData info = req.get_file_value("info");	// 视频简介
			httplib::MultipartFormData video = req.get_file_value("video"); // 视频文件
			httplib::MultipartFormData image = req.get_file_value("image"); // 图片文件
			// MultipartFormData {name, content_type, filename, content}
			std::string video_name = name.content;
			std::string video_info = info.content;
			// ./www/image/变形金刚a.jpg
			std::string root = WWWROOT;
			std::string video_path = root + VIDEO_ROOT + video_name + video.filename;
			std::string image_path = root + IMAGE_ROOT + video_name + image.filename;

			if (FileUtil(video_path).SetContent(video.content) == false)
			{
				rsp.status = 500;
				rsp.body = R"({"result":false, "reason":"视频文件存储失败"})";
				rsp.set_header("Content-Type", "application/json");
				return;
			}
			if (FileUtil(image_path).SetContent(image.content) == false)
			{
				rsp.status = 500;
				rsp.body = R"({"result":false, "reason":"图片文件存储失败"})";
				rsp.set_header("Content-Type", "application/json");
				return;
			}
			Json::Value video_json;
			video_json["name"] = video_name;
			video_json["info"] = video_info;
			video_json["video"] = VIDEO_ROOT + video_name + video.filename; // /video/变形金刚robot.mp4
			video_json["image"] = IMAGE_ROOT + video_name + image.filename; // /video/变形金刚robot.mp4
			if (tb_video->Insert(video_json) == false)
			{
				rsp.status = 500;
				rsp.body = R"({"result":false, "reason":"数据库新增数据失败"})";
				rsp.set_header("Content-Type", "application/json");
				return;
			}
			rsp.set_redirect("/index.html", 303);
			return;
		}
		static void Delete(const httplib::Request &req, httplib::Response &rsp)
		{
			// 1. 获取要删除 的视频ID
			int video_id = std::stoi(req.matches[1]);
			// 2. 删除视频以及图片文件
			Json::Value video;
			if (tb_video->SelectOne(video_id, &video) == false)
			{
				rsp.status = 500;
				rsp.body = R"({"result":false, "reason":"不存在视频信息"})";
				rsp.set_header("Content-Type", "application/json");
				return;
			}
			std::string root = WWWROOT;
			std::string video_path = root + video["video"].asString();
			std::string image_path = root + video["image"].asString();
			remove(video_path.c_str());
			remove(image_path.c_str());
			// 4. 删除数据库信息
			if (tb_video->Delete(video_id) == false)
			{
				rsp.status = 500;
				rsp.body = R"({"result":false, "reason":"删除数据库信息失败"})";
				rsp.set_header("Content-Type", "application/json");
				return;
			}
			return;
		}
		static void Update(const httplib::Request &req, httplib::Response &rsp)
		{
			// 1. 获取要修改的视频信息 1. 视频id， 2. 修改后的信息
			int video_id = std::stoi(req.matches[1]);
			Json::Value video;
			if (JsonUtil::UnSerialize(req.body, &video) == false)
			{
				rsp.status = 400;
				rsp.body = R"({"result":false, "reason":"新的视频信息格式解析失败"})";
				rsp.set_header("Content-Type", "application/json");
				return;
			}
			// 2. 修改数据库数据
			if (tb_video->Update(video_id, video) == false)
			{
				rsp.status = 500;
				rsp.body = R"({"result":false, "reason":"修改数据库信息失败"})";
				rsp.set_header("Content-Type", "application/json");
				return;
			}
			return;
		}
		static void SelectOne(const httplib::Request &req, httplib::Response &rsp)
		{
			// 1. 获取视频的ID
			int video_id = std::stoi(req.matches[1]);
			// 2. 在数据库中查询指定视频信息
			Json::Value video;
			if (tb_video->SelectOne(video_id, &video) == false)
			{
				rsp.status = 500;
				rsp.body = R"({"result":false, "reason":"查询数据库指定视频信息失败"})";
				rsp.set_header("Content-Type", "application/json");
				return;
			}
			// 3. 组织响应正文--json格式的字符串
			JsonUtil::Serialize(video, &rsp.body);
			rsp.set_header("Content-Type", "application/json");
			return;
		}
		static void SelectAll(const httplib::Request &req, httplib::Response &rsp)
		{
			// /video   &    /video?search="关键字"
			bool select_flag = true; // 默认所有查询
			std::string search_key;
			if (req.has_param("search") == true)
			{
				select_flag = false; // 模糊匹配
				search_key = req.get_param_value("search");
			}
			Json::Value videos;
			if (select_flag == true)
			{
				if (tb_video->SelectAll(&videos) == false)
				{
					rsp.status = 500;
					rsp.body = R"({"result":false, "reason":"查询数据库所有视频信息失败"})";
					rsp.set_header("Content-Type", "application/json");
					return;
				}
			}
			else
			{
				if (tb_video->SelectLike(search_key, &videos) == false)
				{
					rsp.status = 500;
					rsp.body = R"({"result":false, "reason":"查询数据库匹配视频信息失败"})";
					rsp.set_header("Content-Type", "application/json");
					return;
				}
			}
			JsonUtil::Serialize(videos, &rsp.body);
			rsp.set_header("Content-Type", "application/json");
			return;
		}

	public:
		Server(int port) : _port(port) {}
		bool RunModule()
		{
			// 1. 初始化操作---初始化数据管理模块，创建指定的目录
			tb_video = new TableVideo();
			FileUtil(WWWROOT).CreateDirectory();
			std::string root = WWWROOT;
			std::string video_real_path = root + VIDEO_ROOT; // ./www/video/
			FileUtil(video_real_path).CreateDirectory();
			std::string image_real_path = root + IMAGE_ROOT; // ./www/image/
			FileUtil(image_real_path).CreateDirectory();
			// 2. 搭建http服务器，开始运行
			//	1. 设置静态资源根目录
			_srv.set_mount_point("/", WWWROOT);
			//	2. 添加请求-处理函数映射关系
			_srv.Post("/video", Insert);
			_srv.Delete("/video/(\\d+)", Delete);
			_srv.Put("/video/(\\d+)", Update);
			_srv.Get("/video/(\\d+)", SelectOne);
			_srv.Get("/videos", SelectAll);
			//	3. 启动服务器
			_srv.listen("0.0.0.0", _port);
			return true;
		}
	};
}
